﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Reflection;
using JQN = JQuery.Net.UI;
using JQuery.Net.Modules;
using HTML = System.Web.UI.HtmlControls;
using System.IO;

namespace JQuery.Net.Controls.Gadgets
{
    [ToolboxData("<{0}:GadgetZone runat=server></{0}:GadgetZone>")]
    [PersistChildren(false), ParseChildren(true)]
    public class GadgetZone
        : JQN.jQNetControl
        , IGadgetZone
        , ICallbackEventHandler
    {
        #region fields
        private List<IGadget> gadgets;
        #endregion

        #region constructors
        public GadgetZone()
            : base(HtmlTextWriterTag.Div)
        {
            Mode = JQNGadgetZoneMode.display;
            Type = JQNGadgetZoneType.gadget;
            Dock = JQNDockLocation.none;

            gadgets = new List<IGadget>();

            ///Initialized defaults: these values here will be overridden by any attributes set in the designer
            Height = new Unit(350, UnitType.Pixel);
            Width = new Unit(100, UnitType.Percentage);
        }
        #endregion

        #region properties
        public JQNDockLocation Dock { get; set; }
        /// <summary>
        /// Get or Set the Title of the Gadget Zone
        /// </summary>
        [PersistenceMode(PersistenceMode.Attribute), DisplayName("Title"), Description("Friendly Name that defines a name for the gadget zone."), Browsable(true)]
        public string Title { get; set; }
        /// <summary>
        /// Get the current mode for this gadget zone.
        /// </summary>
        [Browsable(false)]
        public JQNGadgetZoneMode Mode { get; internal set; }
        /// <summary>
        /// Get or Set the type of the Gadget Zone. I.E.: Defaults to a standard Gadget Zone
        /// </summary>
        [PersistenceMode(PersistenceMode.Attribute), DisplayName("Zone Type"), Description("determines the type of zone and how it will be rendered on the page."), Browsable(true)]
        public JQNGadgetZoneType Type { get; set; }
        /// <summary>
        /// Get or Set a flag that will show a action menu on the zone header or the zone context menu.
        /// </summary>
        [PersistenceMode(PersistenceMode.Attribute), DisplayName("Show Action Menu"), Description("Render a menu with available actions that can be triggered via the zone header or the zone context menu."), Category("Appearance"), Browsable(true)]
        public bool ShowActionMenu { get; set; }
        /// <summary>
        /// Get or Set the icon for the action button
        /// </summary>
        [DisplayName("Action Icon"), Category("Appearance"), DefaultValue("ui-icon-triangle-1-s")]
        public string ActionIcon { get; set; }
        /// <summary>
        /// Get or Set a flag that will show a action menu on the zone header or the zone context menu.
        /// </summary>
        [PersistenceMode(PersistenceMode.Attribute), DisplayName("Show Zone Header"), Description("Render the header region of the gadget zone."), Category("Appearance"), Browsable(true)]
        public bool ShowZoneHeader { get; set; }
        /// <summary>
        /// Get or Set a flag that will enable the zone context menu
        /// </summary>
        [PersistenceMode(PersistenceMode.Attribute), DisplayName("Enable Context Menu"), Description("enable a context menu for the zone."), Category("Behavior"), Browsable(true)]
        public bool EnableContextMenu { get; set; }
        /// <summary>
        /// Get or Set if personalization is enableb for this zone
        /// </summary>
        [PersistenceMode(PersistenceMode.Attribute), DisplayName("Is Personalization Enabled"), Description("enable personalization for this zone."), Category("Behavior"), Browsable(true), DefaultValue(true)]
        public bool IsPersonalizationEnabled { get; set; }
        /// <summary>
        /// Get or Set the text used to represent an empty zone place holder
        /// </summary>
        [DisplayName("Empty Zone Text"), Category("Appearance"), Browsable(true), Bindable(false), DefaultValue("[$Title$] does not have any gadgets docked")]
        public string EmptyZoneText { get; set; }
        /// <summary>
        /// Get or Set the Width of the Zone
        /// </summary>
        [DefaultValue(typeof(Unit), "100%")]
        public Unit Width { get; set; }
        /// <summary>
        /// Get or Set the Height of the Zone
        /// </summary>
        [DefaultValue(typeof(Unit), "300px")]
        public Unit Height { get; set; }
        /// <summary>
        /// Get a reference to the GCM for this page
        /// </summary>
        public JQN.GadgetCommunicationManager Manager
        {
            get
            {
                return JQNModule.Composition.GetExportOrDefault<IJQNPlugin>("GCM") as JQN.GadgetCommunicationManager;
            }
        }

        public IEnumerable<IGadget> Gadgets { get { return gadgets; } }

        public IEnumerable<IActionVerb> Actions { get { throw new NotImplementedException(); } }
        #endregion

        #region methods
        protected override void EnsureDefaultValues()
        {
            base.EnsureDefaultValues((oProperty, oAttributes) =>
            {
                bool handled = false;

                if (oProperty.Name.Eq("EmptyZoneText"))
                {
                    object value = null;

                    if (oProperty.Name.Eq("EmptyZoneText"))
                    {
                        value = ((DefaultValueAttribute)oAttributes[0]).Value.ToString().ApplyTokenReplacements(this);
                    }

                    oProperty.SetValue(this, value, null);

                    handled = true;
                }

                return handled;
            });
        }

        protected override void OnInit(EventArgs e)
        {
            base.OnInit(e);

            EnsureDefaultValues();

            Page.InitComplete += new EventHandler(Page_InitComplete);
        }

        void Page_InitComplete(object sender, EventArgs e)
        {
            if (ID.IsNullOrEmpty())
            {
                ID = String.Format("ZONE{0}", ((List<IGadgetZone>)Manager.Zones).IndexOf(this));
            }

            if (!Page.IsCallback)
            {
                CSSRegistration.Registration(new Resource(Resources.Css.ui_gcm, null, typeof(Resource), Resource.ContentTypes.css));
            }

            if (Dock == JQNDockLocation.none && (Type == JQNGadgetZoneType.catalog || Type == JQNGadgetZoneType.editor))
                Dock = JQNDockLocation.right;

            EnsureChildControls();
        }

        protected override void CreateChildControls()
        {
            HTML.HtmlGenericControl
                header = new HTML.HtmlGenericControl("div"),
                empty = new HTML.HtmlGenericControl("span") { InnerText = EmptyZoneText },
                title = new HTML.HtmlGenericControl("h3") { InnerText = Title },
                area = new HTML.HtmlGenericControl("span");

            header.Attributes.Add("class", "header ui-widget-header ui-corner-all");
            header.Style.Add(HtmlTextWriterStyle.Display, ShowZoneHeader ? "block" : "none");

            title.Attributes.Add("class", "title");

            empty.Attributes.Add("class", "empty");
            empty.Style.Add(HtmlTextWriterStyle.Display, (Mode == JQNGadgetZoneMode.edit && Gadgets.Count() > 0)? "inline-block" : "none");

            header.Controls.Add(title);

            area.Attributes.Add("class", "btns");

            header.Controls.Add(area);

            Controls.Add(header);
            Controls.Add(empty);
        }

        protected override void OnPreRender(EventArgs e)
        {
            base.OnPreRender(e);

            Attributes["role"] = "zone";

            CssClass = "zone ui-widget ui-widget-content".Join(" ", CssClass).Trim();

            if (Dock == JQNDockLocation.none)
            {
                if (!Width.IsEmpty || (Width.Value != 100 && Width.Type != UnitType.Percentage))
                {
                    Style.Add("width", Width.ToString());
                }
                else
                {
                    Style.Add("display", "block");
                }
            }
            else
            {
                Style.Add("display", "none");
            }

            if (!Height.IsEmpty)
            {
                Style.Add("height", Height.ToString());
            }
        }
        #endregion

        public override void RegisterJQNScriptInclude(ResourceManager manager, JQNRegistration options)
        {
            base.RegisterJQNScriptInclude(manager, options);

            /// Create the resource and add it to the manager
            //manager.Add(new Resource(Resources.JQN.ui_callback, GetType(), Resource.ContentTypes.javascript));
            manager.Add(new Resource(Resources.JQN.ui_gadget, GetType(), Resource.ContentTypes.javascript));
            manager.Add(new Resource(Resources.JQN.ui_button, GetType(), Resource.ContentTypes.javascript));
            manager.Add(new Resource(Resources.JQN.ui_tabs, GetType(), Resource.ContentTypes.javascript));
        }

        public override void RegisterJQNScriptStartup(StringWriter writer)
        {
            writer.WriteLine(String.Format("\t$.gcm.zones.add(new zone({0}));", Manager.ZoneSettingsToJSON(this)));
        }

        public override void RaiseCallbackEvent(string arguments)
        {
            base.RaiseCallbackEvent(arguments);

            switch (Arguments.Event)
            {
                case jQNetEvents.command:
                    {   // using brackets here isolates the code from other defined variables in the switch statement.
                        switch ((string)Arguments["cmd"])
                        {
                            default:
                                break;
                        }
                    }
                    break;
                case jQNetEvents.template:
                case jQNetEvents.change:
                default:
                    if (!Arguments.IsHandled)
                    { // event was not handled
                    }
                    return;
            }

            Arguments.IsHandled = true;
        }
    }
}
